// dyngen.cpp : Defines the entry point for the console application.
//

#include "functiondef.h"
#include <ostream>
#include <iostream>
#include <fstream>
using namespace dyngen;
bool defineFptr(std::ostream& target, const FunctionDef& fd) {
	target << fd.returnType() << " (*" << fd.name() << ")" << formatParamVec(fd.paramVec()) << ";" << std::endl;
	return true;
}
bool importFunction(std::ostream& target, const FunctionDef& fd) {
	target << fd.name() << " = " << fd.functionPtrType() << "GetProcAddress(module, \"" << fd.name() << "\");" << std::endl;
	target << "if(!" << fd.name() << ") {\n\tprintf(\"Failed to import function " << fd.name() << "\");\n\treturn 1;\n}" << std::endl;
	return true;
}

bool exportFunctions(std::ostream& target, const FunctionDefVec& functions) {
	// Include necessary headers
	target << "#include <windows.h>" << std::endl;
	target << "#include <stdio.h>" << std::endl;
	// Define function pointers for all functions to be imported
	FunctionDefVec::const_iterator it = functions.begin();
	for(; it != functions.end(); it++) {
		if(!defineFptr(target, *it)) {
			std::cerr << "Failed to define function pointer for function " << it->name() << std::endl;
			return false;
		}
	}
	// define the function that loads the dll Insert boilerplate for loading the dll
	target << "#ifdef __cplusplus" << std::endl; 
	target << "extern \"C\"{" << std::endl;
	target << "#endif // __cplusplus" << std::endl; 
	target << "int loadFunctions(const char* dllPath) {" << std::endl;
	target << "HMODULE module = LoadLibraryA(dllPath);" << std::endl;
	target << "if(!module){" << std::endl;
	target << "\tprintf(\"Failed to load the dll %s\\n\", dllPath);" << std::endl;
	target << "\treturn 1;" << std::endl;
	target << "}" << std::endl;
	
	it = functions.begin();
	for(; it != functions.end(); it++) {
		if(!importFunction(target, *it)) {
			std::cerr << "Failed to generate import code for function " << it->name() << "\\n\");" << std::endl;
			return false;
		}

	}
	// insert end of the boilerplate
	target << "return 0;" << std::endl;
	target << "}" << std::endl;
	target << "#ifdef __cplusplus" << std::endl; 
	target << "} // extern \"C\"" << std::endl;
	target << "#endif // __cplusplus" << std::endl; 

	return true;
}
int main(int argc, char* argv[])
{
	if(argc != 2) {
		std::cerr << "Incorrect number of command line parameters given" << std::endl;
		return 1;
	}
	StringVec paramList;
	paramList.push_back("int");
	paramList.push_back("int");
	FunctionDefVec fdv;
	fdv.push_back(FunctionDef("dllMultiply", "int", paramList));
	if(!exportFunctions(std::cout, fdv)) {
		std::cerr << "Failed export functions" << std::endl;
		return 1;
	}
	std::ofstream target(argv[1], std::ios::out);
	if(!target) {
		std::cerr << "Error opening target file " << argv[1] << std::endl;
		return 1;
	}
	if(!exportFunctions(target, fdv)) {
		std::cerr << "Failed export functions" << std::endl;
		return 1;
	}
	target.close();
	return 0;
}

